# -*- coding: utf-8 -*-
#装饰器编写

#1.无参数的装饰器，例如记录运行时间的装饰器
import time
def record_time(func):  #传递函数
    def wapper(*keys,**args): #传递参数
        start_time=time.time()
        func(*keys,**args)
        end_time=time.time()
        print(end_time-start_time)
    return wapper

@record_time
def work():
    #dosomething
    time.sleep(1)

#2.带参数的装饰器，例如重试程序
def retry(retry_times):
    def method(func):
        def wapper(*key,**args):
            for i in range(retry_times):
                func(*key,**args)
        return wapper
    return method
@retry(5)
def re_work():
    print("test")



#常用装饰器，@property,@staticmethod,@classmethod
#1.@property:被修饰的方法，使其能够像属性一样访问，可以使用@property装饰器来创建只读属性
#@setter:可用来创建只写属性；@delete：可用来创建可读可写属性

#2.@staticmethod：将类中的方法装饰为静态方法，即类不需要创建实例的情况下，可以通过类名直接引用，到达将函数功能与实例解绑的效果。

#3.@classmethod:  类方法的第一个参数是一个类，是将类本身作为操作的方法,类方法被哪个类调用，就传入哪个类作为第一个参数进行操作。


#静态方法和类方法区别
    #静态方法
        #静态方法是类中的函数，不需要实例。静态方法主要是用来存放逻辑性的代码，逻辑上属于类，但是和类本身没有关系，
        # 也就是说在静态方法中，不会涉及到类中的属性和方法的操作。可以理解为，静态方法是个独立的、单纯的函数，
        # 它仅仅托管于某个类的名称空间中，便于使用和维护。
    #类方法
        #原则上，类方法是将类本身作为对象进行操作的方法。假设有个方法，且这个方法在逻辑上采用类本身作为对象来调用更合理，那么这个方法就可以定义为类方法。另外，如果需要继承，也可以定义为类方法。




#@property,@setter，@deleter
class A():
    def __init__(self):
        pass
    @property
    def name(self):#被修饰的函数名当属性使用
        return self._name
    @name.setter
    def name(self,name_x):
        print('进来了')
        self._name=name_x
    def aaa(self):
        self.name=22#启动setter修饰的函数   
    @name.deleter
    def name(self):
        del self._name

#@staticmethod
# coding: utf-8
class TestClass:
    name = "test"

    def __init__(self, name):
        self.name = name

    @staticmethod
    def fun(self, x, y):
        return  x + y

cls = TestClass("felix")
print("通过实例引用方法")
print(cls.fun(None, 2, 3)) # 参数个数必须与定义中的个数保持一致，否则报错

print("类名直接引用静态方法")
print(TestClass.fun(None, 2, 3)) # 参数个数必须与定义中的个数保持一致，否则报错————————————————

#classmethod
# coding: utf-8
class Car(object):
    car = "audi"
    @classmethod
    def value(self, category): # 可定义多个参数，但第一个参数为类本身
        print("%s car of %s" % (category, self.car))

class BMW(Car):
    car = "BMW"

class Benz(Car):
    car = "Benz"

print("通过实例调用")
baoma = BMW()
baoma.value("Normal") # 由于第一个参数为类本身，调用时传入的参数对应的是category

print("通过类名直接调用")
Benz.value("SUV")




#重试装饰器，错误则重试，成功则不重试

def failed_retry(times):
    def get_fun(fun):
        def wapper(*keys,**args):
            for i in range(times):
                try:
                    if fun(*keys,**args):
                        return True
                except:
                    continue

        return wapper
    return get_fun
@failed_retry(3)
def connect_network():
    if connect_success:
        return True
    else:
        return False



##示例
import random
import time
from functools import wraps


def fail_retry(try_times, time_delay):
    def decorator(func):
        @wraps(func)
        def wrapper():
            n = 1
            current_result = func()
            while not current_result:
                print(f"开始第{n}次重试....")
                time.sleep(time_delay)
                retry_result = func()       
                if retry_result:
                    current_result = retry_result
                    break
                n += 1
                if n > try_times:
                    break
            return current_result
        return wrapper
    return decorator


@fail_retry(try_times=5, time_delay=1)
def test():
    try:
        return 10 / random.randint(0, 1)
    except Exception as e:
        print(f"执行失败，当前执行错误码为：{e}")
        return None


for i in range(1, 10):
    print(f"{'='*10}开始第{i}次测试{'='*10}")
    print(f"测试成功的的结果是：{test()}")

if __name__=='__main__':
    work()#不带参，装饰器
    re_work()#带参装饰器


